import asyncio
import socket
import threading
import time
import re
import struct
import io
import os
from multiprocessing import Process
import websockets
import redis
from temp import get_len_by_value, get_time
from util import *
from concurrent.futures import ThreadPoolExecutor


# ws_url = 'ws://10.100.12.58:18088'

# final_time = {}
# connect_dict = {}


async def send_rtsp_data(flag, fileNameList, ws_url, final_time):
    print("video send data", fileNameList)

    # 发送第一帧时间戳给到中台
    # fileNameList = fileList[0]
    with open(fileNameList, 'rb') as f:
        fileSize = int(f.seek(0, io.SEEK_END))
        f.seek(0, 0)
        nowPosition = 0
        print(nowPosition, fileSize)
        while nowPosition < fileSize:
            byteHeadLen = f.read(4)
            HeadLen = struct.unpack("<I", byteHeadLen)[0]
            byteMsgLen = f.read(4)
            MsgLen = struct.unpack("<I", byteMsgLen)[0]
            byteHead = f.read(HeadLen)
            timeStamp = struct.unpack("<Q", byteHead)[0]
            img_data1 = f.read(MsgLen)
            file_name = timeStamp
            nowPosition = nowPosition + 16 + MsgLen
            print("发送时间戳", str(timeStamp))
            async with websockets.connect(ws_url) as websocket:
                await websocket.send(str(timeStamp))
                response = await websocket.recv()
                final_timestamp = int(response)
                print(f"相机video received: {response}")
                final_time[flag] = response
            break


def delete_rtsp_connect(connect_dict, Flag, c):
    c.close()
    connect = connect_dict[Flag]
    connect.remove(c)
    connect_dict[Flag] = connect


def rtsp_connect(server_socket, flag, host, port, connect_dict):
    while True:
        # 等待客户端连接
        print("Waiting for a connection...")
        connection, client_address = server_socket.accept()

        try:
            print(f"Connection from {client_address}")

            # 接收并处理数据（可选）
            while True:
                data = connection.recv(1024)
                if not data:
                    print("No more data from", client_address)
                    break
                print(f"Received '{data.decode()}' from {client_address}")

                if "OPTIONS" in data.decode():
                    match = re.search(r'CSeq: (\d+)', data.decode())
                    cseq_value = '2'
                    if match:
                        cseq_value = match.group(1)

                    response = b'RTSP/1.0 200 OK\r\nCSeq: ' + cseq_value.encode(
                        'utf-8') + b'\r\nServer: Rtsp Server/3.0\r\nPublic: OPTIONS, DESCRIBE, ANNOUNCE, SETUP, PLAY, RECORD, PAUSE, TEARDOWN, SET_PARAMETER, GET_PARAMETER\r\n\r\n'
                    connection.sendall(response)
                if "DESCRIBE" in data.decode():
                    cseq_value = '3'
                    match = re.search(r'CSeq: (\d+)', data.decode())
                    if match:
                        cseq_value = match.group(1)

                    original_bytes = b'\r\nx-Accept-Dynamic-Rate: 1\r\nContent-Base: rtsp://admin:wanji123@'
                    target_path = b'/cam/realmonitor?channel=1&subtype=0/\r\nCache-Control: must-revalidate\r\nContent-Length: 465\r\nContent-Type: application/sdp\r\n\r\nv=0\r\no=- 2251944609 2251944609 IN IP4 0.0.0.0\r\ns=Media Server\r\nc=IN IP4 0.0.0.0\r\nt=0 0\r\na=control:*\r\na=packetization-supported:DH\r\na=rtppayload-supported:DH\r\na=range:npt=now-\r\nm=video 0 RTP/AVP 96\r\na=control:trackID=0\r\na=framerate:10.000000\r\na=rtpmap:96 H264/90000\r\na=fmtp:96 packetization-mode=1;profile-level-id=64002A;sprop-parameter-sets=Z2QAKqwsaoHgCJ+WbgoCCgQA,aO4xshsA\r\na=recvonly\r\nm=audio 0 RTP/AVP 8\r\na=control:trackID=1\r\na=rtpmap:8 PCMA/8000\r\na=recvonly\r\n'
                    formatted_string = f"{host}:{port}"
                    # 转换为字节串
                    new_part_bytes = formatted_string.encode()
                    # 拼接所有部分
                    final_bytes = original_bytes + new_part_bytes + target_path

                    response = b'RTSP/1.0 200 OK\r\nCSeq: ' + cseq_value.encode(
                        'utf-8') + final_bytes

                    connection.sendall(response)
                if "SETUP" in data.decode():
                    match = re.search(r'CSeq: (\d+)', data.decode())
                    cseq_value = '5'
                    if match:
                        cseq_value = match.group(1)
                        print("cseq_value", cseq_value)  # 输出: 5
                    response = b'RTSP/1.0 200 OK\r\nCSeq: ' + cseq_value.encode(
                        'utf-8') + b'\r\nSession: 6611061302;timeout=60\r\nTransport: RTP/AVP/TCP;unicast;interleaved=0-1;ssrc=772D9243\r\nx-Dynamic-Rate: 1\r\n\r\n'
                    connection.sendall(response)
                # 发送数据回客户端（可选）
                # response = "Hello, client!".encode('utf-8')
                # connection.sendall(response)
                if "PLAY" in data.decode():
                    cseq_value = '6'
                    match = re.search(r'CSeq: (\d+)', data.decode())
                    if match:
                        cseq_value = match.group(1)
                    response = b'RTSP/1.0 200 OK\r\nCSeq: ' + cseq_value.encode(
                        'utf-8') + b'\r\nSession: 6611061302\r\nRTP-Info: url=trackID=0;seq=23978;rtptime=23978\r\n\r\n'
                    connection.sendall(response)
                    if flag not in connect_dict.keys():
                        connect_dict[flag] = [connection]
                    else:
                        temp = connect_dict[flag]
                        temp.append(connection)
                        connect_dict[flag] = temp
                    break
        except Exception as e:
            print(str(e))
        finally:
            time.sleep(0.1)


def start_video_server(video_id, video_dict, final_time, connect_dict):
    host = video_dict['video_host']
    port = video_dict['video_port']
    fileList = video_dict['video_files']
    Flag = video_id
    fps = video_dict['video_fps']
    ws_url = video_dict['ws_url']
    stationNum = video_dict['station_name']
    # 创建一个socket对象
    server_socket = socket.socket(socket.AF_INET, socket.SOCK_STREAM)

    # 绑定到指定地址和端口
    server_address = (host, port)
    print(f"Starting up on {server_address} ...")
    server_socket.bind(server_address)
    print("绑定端口", (host, port))
    # 开始监听连接
    server_socket.listen(1)
    threading.Thread(target=rtsp_connect, args=(server_socket, Flag, host, port, connect_dict)).start()

    # 发送第一帧时间戳给到中台
    loop = asyncio.new_event_loop()
    asyncio.set_event_loop(loop)
    # print("fileList", fileList)
    loop.run_until_complete(send_rtsp_data(Flag, fileList[0], ws_url, final_time))
    # print("!!!!!!收到消息")
    # 等待反馈最大的时间戳
    largst_time = None
    while True:
        if final_time[Flag]:
            largst_time = final_time[Flag]
            # print("rtsp_largst_time", largst_time)
            break
        time.sleep(0.01)
    # print("!!!!!!开始发送数据")

    executor = ThreadPoolExecutor(max_workers=5)
    count = 0
    before_time = None
    for fileNameList in fileList:
        with open(fileNameList, 'rb') as f:
            fileSize = int(f.seek(0, io.SEEK_END))
            f.seek(0, 0)
            nowPosition = 0
            while nowPosition < fileSize:
                start_time = time.time()
                byteHeadLen = f.read(4)
                HeadLen = struct.unpack("<I", byteHeadLen)[0]
                byteMsgLen = f.read(4)
                MsgLen = struct.unpack("<I", byteMsgLen)[0]
                byteHead = f.read(HeadLen)
                timeStamp = struct.unpack("<Q", byteHead)[0]
                img_data1 = f.read(MsgLen)
                file_name = timeStamp
                nowPosition = nowPosition + 16 + MsgLen
                # print("video time",timeStamp)
                # 略过前几帧

                if (int(timeStamp) - int(largst_time)) < 0:
                    # print("略过前几帧")
                    continue

                current_time = time.time()
                if fps == 0:
                    if before_time:
                        try:
                            time.sleep((timeStamp - before_time) / 1000)
                        except Exception as e:
                            print(e)
                    else:
                        print("第一帧时间", timeStamp, largst_time, int(timeStamp) - int(largst_time),
                              int(time.time() * 1000) - int(largst_time))
                    before_time = timeStamp
                if fps > 0:
                    if before_time:
                        if target_len > 800:
                            if (current_time - before_time) > 1 / fps:
                                print("单帧耗时过大")
                            else:
                                time.sleep(1 / fps - (current_time - before_time))
                    before_time = current_time

                # print('video id', video_id, 'timeStamp', timeStamp, 'current_time', current_time)
                # r.set(video_id, str({"stationNum": stationNum, "ip": host, "port": port, "fps": fps, "time": timeStamp,
                #                      "dataSource": fileNameList, "state": 0}))
                # threading.Thread(target=send_redis_hset, args=("deviceInfo", video_id,
                #                                                str({"stationNum": stationNum, "ip": host, "port": port,
                #                                                     "fps": fps, "time": timeStamp,
                #                                                     "dataSource": fileNameList, "state": 0}))).start()
                executor.submit(send_redis_hset, "deviceInfo", video_id,
                                str({"stationNum": stationNum, "ip": host, "port": port,
                                     "fps": fps, "time": timeStamp,
                                     "dataSource": fileNameList, "state": 0}))
                target_time = timeStamp + 2208988800000
                s = int(str(target_time)[:10])
                ms = int(str(target_time)[10:13])
                # if largst_time - timeStamp > 100:
                #     continue
                s_data_bytes, ms_data_bytes = get_time(s, ms)

                target_data = img_data1[5:]
                target_len = MsgLen - 5
                flag = img_data1[4:5]
                if flag == b'e' or flag == b'g':
                    if flag == b'e':
                        wei_start = b'|\x85'
                    if flag == b'g':
                        wei_start = b'|\x87'
                    wei_mid = b'|\x05'
                    wei_end = b'|E'
                if flag == b'a':
                    wei_start = b'|\x81'
                    wei_mid = b'|\x01'
                    wei_end = b'|A'
                if target_len <= 800:
                    response = b'$\x00' + get_len_by_value(len(img_data1[4:]) + 28) + \
                               b'\x90\xe0' + \
                               struct.pack('!H', count % 65535) \
                               + b'\x00\x03\x1e\xa8' \
                                 b'rV\x89\xb8' \
                                 b'\xab\xad\x00\x03' \
                               + s_data_bytes + ms_data_bytes \
                               + b'\x00\x00\x00\x00' \
                               + img_data1[4:]
                    count += 1
                    if Flag in connect_dict.keys():
                        connection = connect_dict[Flag]
                        # print("发送消息")
                        for c in connection:
                            try:
                                c.sendall(response)
                            except Exception as e:
                                delete_rtsp_connect(connect_dict, Flag, c)
                                continue
                else:
                    num = int(target_len / 800)
                    div = target_len % 800

                    for i in range(num + 1):
                        if i == 0:
                            data = target_data[:800]
                            response = b'$\x00' + get_len_by_value(len(data) + 30) + \
                                       b'\x90\xe0' + \
                                       struct.pack('!H', count % 65535) \
                                       + b'\x00\x03\x1e\xa8' \
                                         b'rV\x89\xb8' \
                                         b'\xab\xad\x00\x03' \
                                       + s_data_bytes + ms_data_bytes \
                                       + b'\x00\x00\x00\x00' \
                                       + wei_start + data
                            count += 1
                            if Flag in connect_dict.keys():
                                connection = connect_dict[Flag]
                                for c in connection:
                                    try:
                                        c.sendall(response)
                                    except Exception as e:
                                        delete_rtsp_connect(connect_dict, Flag, c)
                                        continue
                        elif (i == num and div > 0) or (i == num - 1 and div == 0):

                            data = target_data[i * 800:]
                            response = b'$\x00' + get_len_by_value(len(data) + 30) + \
                                       b'\x90\xe0' + \
                                       struct.pack('!H', count % 65535) \
                                       + b'\x00\x03\x1e\xa8' \
                                         b'rV\x89\xb8' \
                                         b'\xab\xad\x00\x03' \
                                       + s_data_bytes + ms_data_bytes \
                                       + b'\x00\x00\x00\x00' \
                                       + wei_end + data
                            count += 1
                            if Flag in connect_dict.keys():
                                connection = connect_dict[Flag]
                                for c in connection:
                                    try:
                                        c.sendall(response)
                                    except Exception as e:
                                        delete_rtsp_connect(connect_dict, Flag, c)
                                        continue
                            break
                        else:
                            data = target_data[i * 800:(i + 1) * 800]
                            response = b'$\x00' + get_len_by_value(len(data) + 30) + \
                                       b'\x90\xe0' + \
                                       struct.pack('!H', count % 65535) \
                                       + b'\x00\x03\x1e\xa8' \
                                         b'rV\x89\xb8' \
                                         b'\xab\xad\x00\x03' \
                                       + s_data_bytes + ms_data_bytes \
                                       + b'\x00\x00\x00\x00' \
                                       + wei_mid + data
                            count += 1
                            # print(connect_dict.keys(),Flag in connect_dict.keys(),print(Flag))
                            if Flag in connect_dict.keys():
                                # print("发送消息")
                                connection = connect_dict[Flag]
                                for c in connection:
                                    try:
                                        c.sendall(response)
                                    except Exception as e:
                                        delete_rtsp_connect(connect_dict, Flag, c)
                                        continue
                # end_time = time.time()
                # if fps == 0:
                #     if before_time:
                #         time.sleep((timeStamp - before_time) / 1000)
                #     before_time = timeStamp
                # if fps > 0:
                #     if target_len > 800:
                #         if (end_time - start_time) > 1 / fps:
                #             print("单帧耗时过大")
                #         else:
                #             time.sleep(1 / fps - (end_time - start_time))

        # finally:
        #     # 清理连接
        #     connection.close()


def add_video_server(video_id, video_dict, final_time, connect_dict):
    host = video_dict['video_host']
    port = video_dict['video_port']
    fileList = video_dict['video_files']
    Flag = video_id
    fps = video_dict['video_fps']
    stationNum = video_dict['station_name']
    # 创建一个socket对象
    server_socket = socket.socket(socket.AF_INET, socket.SOCK_STREAM)

    # 绑定到指定地址和端口
    server_address = (host, port)
    print(f"Starting up on {server_address} ...")
    server_socket.bind(server_address)
    print("绑定端口", (host, port))
    # 开始监听连接
    server_socket.listen(1)
    threading.Thread(target=rtsp_connect, args=(server_socket, Flag, host, port, connect_dict)).start()

    time_diff = get_set("time_diff")

    largst_time = int(time.time() * 1000) - time_diff
    executor = ThreadPoolExecutor(max_workers=5)
    count = 0
    before_time = None

    for fileNameList in fileList:
        with open(fileNameList, 'rb') as f:
            fileSize = int(f.seek(0, io.SEEK_END))
            f.seek(0, 0)
            nowPosition = 0
            while nowPosition < fileSize:
                start_time = time.time()
                byteHeadLen = f.read(4)
                HeadLen = struct.unpack("<I", byteHeadLen)[0]
                byteMsgLen = f.read(4)
                MsgLen = struct.unpack("<I", byteMsgLen)[0]
                byteHead = f.read(HeadLen)
                timeStamp = struct.unpack("<Q", byteHead)[0]
                img_data1 = f.read(MsgLen)
                file_name = timeStamp
                nowPosition = nowPosition + 16 + MsgLen
                # print("video time",timeStamp)
                # 略过前几帧
                executor.submit(send_redis_hset, "deviceInfo", video_id,
                                str({"stationNum": stationNum, "ip": host, "port": port,
                                     "fps": fps, "time": timeStamp,
                                     "dataSource": fileNameList, "state": 0}))
                if (int(timeStamp) - int(largst_time)) < 0:
                    # print("略过前几帧")
                    continue

                current_time = time.time()
                if fps == 0:
                    if before_time:
                        try:
                            time.sleep((timeStamp - before_time) / 1000)
                        except Exception as e:
                            print(e)
                    else:
                        print("第一帧时间", timeStamp, largst_time, int(timeStamp) - int(largst_time),
                              int(time.time() * 1000) - int(largst_time))
                    before_time = timeStamp
                if fps > 0:
                    if before_time:
                        if target_len > 800:
                            if (current_time - before_time) > 1 / fps:
                                print("单帧耗时过大")
                            else:
                                time.sleep(1 / fps - (current_time - before_time))
                    before_time = current_time

                # print('video id', video_id, 'timeStamp', timeStamp, 'current_time', current_time)
                # r.set(video_id, str({"stationNum": stationNum, "ip": host, "port": port, "fps": fps, "time": timeStamp,
                #                      "dataSource": fileNameList, "state": 0}))
                threading.Thread(target=send_redis_hset, args=("deviceInfo", video_id,
                                                               str({"stationNum": stationNum, "ip": host, "port": port,
                                                                    "fps": fps, "time": timeStamp,
                                                                    "dataSource": fileNameList, "state": 0}))).start()
                target_time = timeStamp + 2208988800000
                s = int(str(target_time)[:10])
                ms = int(str(target_time)[10:13])
                # if largst_time - timeStamp > 100:
                #     continue
                s_data_bytes, ms_data_bytes = get_time(s, ms)

                target_data = img_data1[5:]
                target_len = MsgLen - 5
                flag = img_data1[4:5]
                if flag == b'e' or flag == b'g':
                    if flag == b'e':
                        wei_start = b'|\x85'
                    if flag == b'g':
                        wei_start = b'|\x87'
                    wei_mid = b'|\x05'
                    wei_end = b'|E'
                if flag == b'a':
                    wei_start = b'|\x81'
                    wei_mid = b'|\x01'
                    wei_end = b'|A'
                if target_len <= 800:
                    response = b'$\x00' + get_len_by_value(len(img_data1[4:]) + 28) + \
                               b'\x90\xe0' + \
                               struct.pack('!H', count % 65535) \
                               + b'\x00\x03\x1e\xa8' \
                                 b'rV\x89\xb8' \
                                 b'\xab\xad\x00\x03' \
                               + s_data_bytes + ms_data_bytes \
                               + b'\x00\x00\x00\x00' \
                               + img_data1[4:]
                    count += 1
                    if Flag in connect_dict.keys():
                        connection = connect_dict[Flag]
                        # print("发送消息")
                        for c in connection:
                            try:
                                c.sendall(response)
                            except Exception as e:
                                delete_rtsp_connect(connect_dict, Flag, c)
                                continue
                else:
                    num = int(target_len / 800)
                    div = target_len % 800

                    for i in range(num + 1):
                        if i == 0:
                            data = target_data[:800]
                            response = b'$\x00' + get_len_by_value(len(data) + 30) + \
                                       b'\x90\xe0' + \
                                       struct.pack('!H', count % 65535) \
                                       + b'\x00\x03\x1e\xa8' \
                                         b'rV\x89\xb8' \
                                         b'\xab\xad\x00\x03' \
                                       + s_data_bytes + ms_data_bytes \
                                       + b'\x00\x00\x00\x00' \
                                       + wei_start + data
                            count += 1
                            if Flag in connect_dict.keys():
                                connection = connect_dict[Flag]
                                for c in connection:
                                    try:
                                        c.sendall(response)
                                    except Exception as e:
                                        delete_rtsp_connect(connect_dict, Flag, c)
                                        continue
                        elif (i == num and div > 0) or (i == num - 1 and div == 0):

                            data = target_data[i * 800:]
                            response = b'$\x00' + get_len_by_value(len(data) + 30) + \
                                       b'\x90\xe0' + \
                                       struct.pack('!H', count % 65535) \
                                       + b'\x00\x03\x1e\xa8' \
                                         b'rV\x89\xb8' \
                                         b'\xab\xad\x00\x03' \
                                       + s_data_bytes + ms_data_bytes \
                                       + b'\x00\x00\x00\x00' \
                                       + wei_end + data
                            count += 1
                            if Flag in connect_dict.keys():
                                connection = connect_dict[Flag]
                                for c in connection:
                                    try:
                                        c.sendall(response)
                                    except Exception as e:
                                        delete_rtsp_connect(connect_dict, Flag, c)
                                        continue
                            break
                        else:
                            data = target_data[i * 800:(i + 1) * 800]
                            response = b'$\x00' + get_len_by_value(len(data) + 30) + \
                                       b'\x90\xe0' + \
                                       struct.pack('!H', count % 65535) \
                                       + b'\x00\x03\x1e\xa8' \
                                         b'rV\x89\xb8' \
                                         b'\xab\xad\x00\x03' \
                                       + s_data_bytes + ms_data_bytes \
                                       + b'\x00\x00\x00\x00' \
                                       + wei_mid + data
                            count += 1
                            # print(connect_dict.keys(),Flag in connect_dict.keys(),print(Flag))
                            if Flag in connect_dict.keys():
                                # print("发送消息")
                                connection = connect_dict[Flag]
                                for c in connection:
                                    try:
                                        c.sendall(response)
                                    except Exception as e:
                                        delete_rtsp_connect(connect_dict, Flag, c)
                                        continue
                # end_time = time.time()
                # if fps == 0:
                #     if before_time:
                #         time.sleep((timeStamp - before_time) / 1000)
                #     before_time = timeStamp
                # if fps > 0:
                #     if target_len > 800:
                #         if (end_time - start_time) > 1 / fps:
                #             print("单帧耗时过大")
                #         else:
                #             time.sleep(1 / fps - (end_time - start_time))

        # finally:
        #     # 清理连接
        #     connection.close()


def video_run(config_json):
    final_time = {}
    connect_dict = {}
    fileNameList = {}

    file_path = config_json['file_path']
    local_ip = config_json['local_ip']
    websocket_port = config_json['websocket_port']
    station_num = len(config_json['station'])
    for i in range(station_num):
        # 获取各个基站信息
        station = config_json['station'][i]
        station_path = os.path.join(file_path, station['name'])
        # video 目录
        video_path = os.path.join(station_path, 'video')
        # video
        video_num = len(station['video'])
        video_flag = True
        for v in range(video_num):
            if video_flag:
                video_id = int((int(station['name']) - 1) * 3)
                video_flag = False
            else:
                video_id = int((int(station['name']) - 1) * 3 + 2)
            video_files = get_folders(video_path, video_id)
            video_host = station['video'][v]['rtsp_host']
            video_port = station['video'][v]['rtsp_port']
            video_fps = station['video'][v]['fps']
            if video_host == "127.0.0.1":
                while is_port_in_use(video_host, video_port):
                    time.sleep(0.1)
            ws_url = 'ws://' + str(local_ip) + ':' + str(websocket_port) + '/' + str(station['name']) + '/video/' + str(
                video_id)
            fileNameList[video_id] = {
                'video_files': video_files,
                'video_host': video_host,
                'video_port': video_port,
                'video_fps': video_fps,
                'ws_url': ws_url,
                "station_name": station['name']
            }

    for k, v in fileNameList.items():
        Process(target=start_video_server, args=(k, v, final_time, connect_dict,)).start()
        # video_process.start()
        # threading.Thread(target=start_video_server, args=(k, v, final_time, connect_dict,)).start()


def video_run_add(config_json):
    connect_dict = {}
    fileNameList = {}

    file_path = config_json['file_path']
    local_ip = config_json['local_ip']

    # 获取各个基站信息
    station = {
        "name": "1",
        "video": [
            {
                "rtsp_host": "10.100.12.33",
                "rtsp_port": 554,
                "fps": 0
            },
            {
                "rtsp_host": "10.100.12.33",
                "rtsp_port": 555,
                "fps": 0
            }
        ]
    }
    station_path = os.path.join(file_path, station['name'])
    # video 目录
    video_path = os.path.join(station_path, 'video')
    # video
    video_num = len(station['video'])
    video_flag = True
    for v in range(video_num):
        if video_flag:
            video_id = int((int(station['name']) - 1) * 3)
            video_flag = False
        else:
            video_id = int((int(station['name']) - 1) * 3 + 2)
        video_files = get_folders(video_path, video_id)
        video_host = station['video'][v]['rtsp_host']
        video_port = station['video'][v]['rtsp_port']
        video_fps = station['video'][v]['fps']

        fileNameList[video_id] = {
            'video_files': video_files,
            'video_host': video_host,
            'video_port': video_port,
            'video_fps': video_fps,
            "station_name": station['name']
        }

    for k, v in fileNameList.items():
        Process(target=add_video_server, args=(k, v, connect_dict,)).start()
        # video_process.start()
        # threading.Thread(target=start_video_server, args=(k, v, final_time, connect_dict,)).start()


if __name__ == "__main__":
    config_json = {}
    video_run(config_json)
